package com.tbit.uqbike.center.util;

import com.tbit.uqbike.center.pojo.Point;

import java.util.ArrayList;
import java.util.List;

/**
 * 电子围栏工具类
 *
 * @author Leon
 * 2017年12月13日 下午7:57:27
 */
public class GeoUtil {
    /**
     * 判断点是否在多边形内
     *
     * @param point  检测点
     * @param points 多边形的顶点
     * @return 点在多边形内返回true, 否则返回false
     */
    public static boolean IsPtInPoly(Point point, List<Point> points) {
        int N = points.size();
        boolean boundOrVertex = true; //如果点位于多边形的顶点或边上，也算做点在多边形内，直接返回true  
        int intersectCount = 0;//cross points count of x   
        double precision = 2e-10; //浮点类型计算时候与0比较时候的容差  
        Point p1, p2;//neighbour bound vertices  
        Point p = point; //当前点  

        p1 = points.get(0);//left vertex          
        for (int i = 1; i <= N; ++i) {//check all rays              
            if (p.equals(p1)) {
                return boundOrVertex;//p is an vertex  
            }

            p2 = points.get(i % N);//right vertex              
            if (p.getX() < Math.min(p1.getX(), p2.getX()) || p.getX() > Math.max(p1.getX(), p2.getX())) {//ray is outside of our interests                  
                p1 = p2;
                continue;//next ray left point  
            }

            if (p.getX() > Math.min(p1.getX(), p2.getX()) && p.getX() < Math.max(p1.getX(), p2.getX())) {//ray is crossing over by the algorithm (common part of)  
                if (p.getY() <= Math.max(p1.getY(), p2.getY())) {//x is before of ray                      
                    if (p1.getX() == p2.getX() && p.getY() >= Math.min(p1.getY(), p2.getY())) {//overlies on a horizontal ray  
                        return boundOrVertex;
                    }

                    if (p1.getY() == p2.getY()) {//ray is vertical                          
                        if (p1.getY() == p.getY()) {//overlies on a vertical ray  
                            return boundOrVertex;
                        } else {//before ray  
                            ++intersectCount;
                        }
                    } else {//cross point on the left side                          
                        double xinters = (p.getX() - p1.getX()) * (p2.getY() - p1.getY()) / (p2.getX() - p1.getX()) + p1.getY();//cross point of y                          
                        if (Math.abs(p.getY() - xinters) < precision) {//overlies on a ray  
                            return boundOrVertex;
                        }

                        if (p.getY() < xinters) {//before ray  
                            ++intersectCount;
                        }
                    }
                }
            } else {//special case when ray is crossing through the vertex                  
                if (p.getX() == p2.getX() && p.getY() <= p2.getY()) {//p crossing over p2                      
                    Point p3 = points.get((i + 1) % N); //next vertex                      
                    if (p.getX() >= Math.min(p1.getX(), p3.getX()) && p.getX() <= Math.max(p1.getX(), p3.getX())) {//p.getX() lies between p1.getX() & p3.getX()  
                        ++intersectCount;
                    } else {
                        intersectCount += 2;
                    }
                }
            }
            p1 = p2;//next ray left point  
        }

        if (intersectCount % 2 == 0) {//偶数在多边形外  
            return false;
        } else { //奇数在多边形内  
            return true;
        }
    }

    /**
     * 经纬度字符串转points
     *
     * @param pointString
     * @return
     */
    public static List<Point> getPoints(String pointString) {
        List<Point> points = new ArrayList<Point>();

        String[] pointArray = pointString.split(";");
        for (int i = 0; i < pointArray.length; i++) {
            String[] lonlat = pointArray[i].split(",");
            if (lonlat.length == 2) {
                points.add(new Point(Double.parseDouble(lonlat[0]), Double.parseDouble(lonlat[1])));
            }
        }

        return points;
    }

    /**
     * Points转字符串
     *
     * @param points
     * @return
     */
    public static String getPointToString(List<Point> points) {
        StringBuilder result = new StringBuilder();
        int size = points.size();
        for (int i = 0; i < size; i++) {
            Point point = points.get(i);
            result.append(String.valueOf(point.getX())).append(",").append(String.valueOf(point.getY()));

            if (i != (size - 1)) {
                result.append(";");
            }
        }

        return result.toString();
    }

    // 测试一个点是否在多边形内  
    public static void main(String[] args) {
        Point point = new Point(115.597662, 39.946361);

        List<Point> pts = new ArrayList<Point>();
        pts.add(new Point(111.30400377834864, 23.488876247192163));
        pts.add(new Point(116.000103, 39.651002));
        pts.add(new Point(116.924567, 39.645669));

        if (IsPtInPoly(point, pts)) {
            System.out.println("点在多边形内");
        } else {
            System.out.println("点在多边形外");
        }
    }

}
